local Guide = {Waypoints = {}, Focus = nil, UserWaypoint = nil}
BtWQuests.Guide = Guide;

function Guide:AddWayPoint(mapId, x, y, name)
    if not self.DataProvider then
        self.DataProvider = CreateFromMixins(BtWQuestsGuideDataProviderMixin)
        LibMapPinHandler[WorldMapFrame]:AddDataProvider(self.DataProvider);
    end

    local continentMapId = mapId
    local mapInfo = C_Map.GetMapInfo(continentMapId)
    while mapInfo and mapInfo.mapType > Enum.UIMapType.Continent do
        continentMapId = mapInfo.parentMapID
        mapInfo = C_Map.GetMapInfo(continentMapId)
    end

    if not continentMapId or not mapInfo then
        return
    end

    local continentId, position = C_Map.GetWorldPosFromMapPos(mapId, {
        x = x,
        y = y,
    })
    if not continentId or not position then
        return
    end
    local _, mapPosition = C_Map.GetMapPosFromWorldPos(continentId, position, continentMapId)
    if not mapPosition then
        continentMapId = mapId
        mapPosition = select(2, C_Map.GetMapPosFromWorldPos(continentId, position, continentMapId))
    end
    if not mapPosition then
        return
    end

    local waypoints = self.Waypoints[continentMapId]
    if not waypoints then
        waypoints = {}
        self.Waypoints[continentMapId] = waypoints
    end

    mapPosition.mapId = continentMapId
    mapPosition.itemName = name
    waypoints[mapPosition] = true
    self:SetFocus(mapPosition)
end
function Guide:SetFocus(item)
    assert(item and item.mapId and self.Waypoints[item.mapId])
    self.Focus = item

    if C_Map and C_Map.SetUserWaypoint then
        local waypoint = UiMapPoint.CreateFromVector2D(item.mapId, item)
        self.UserWaypoint = waypoint
        C_Map.SetUserWaypoint(waypoint)
		C_SuperTrack.SetSuperTrackedUserWaypoint(true)
    end

    if WorldMapFrame:IsShown() then
        self.DataProvider:RefreshAllData()
    end
end

-- /run BtWQuests_QuestDataProvider = CreateFromMixins(BtWQuests_QuestDataProviderMixin);WorldMapFrame:AddDataProvider(BtWQuests_QuestDataProvider);
BtWQuestsGuideDataProviderMixin = CreateFromMixins(MapCanvasDataProviderMixin);
function BtWQuestsGuideDataProviderMixin:OnAdded(mapCanvas)
	MapCanvasDataProviderMixin.OnAdded(self, mapCanvas);
	mapCanvas:SetPinTemplateType("BtWQuestsGuidePinTemplate", "BUTTON");
end
function BtWQuestsGuideDataProviderMixin:RemoveAllData()
	self:GetMap():RemoveAllPinsByTemplate("BtWQuestsGuidePinTemplate");
end
function BtWQuestsGuideDataProviderMixin:RefreshAllData(fromOnShow)
	self:RemoveAllData();

    local mapId = self:GetMap():GetMapID();
    if not mapId then
        return
    end

    local continentMapId = mapId
    local mapInfo = C_Map.GetMapInfo(continentMapId)
    while mapInfo and mapInfo.mapType > Enum.UIMapType.Continent do
        continentMapId = mapInfo.parentMapID
        mapInfo = C_Map.GetMapInfo(continentMapId)
    end

    local waypoints = Guide.Waypoints[continentMapId]
    if not waypoints then
        continentMapId = mapId
        waypoints = Guide.Waypoints[continentMapId]
    end
    if not waypoints then
        return
    end
    for item in pairs(waypoints) do
        local position = item
        if continentMapId ~= mapId then
            local continentId, continentPosition = C_Map.GetWorldPosFromMapPos(continentMapId, item)
            position = select(2, C_Map.GetMapPosFromWorldPos(continentId, continentPosition, mapId))
        end

        if position and position.x > 0 and position.x < 1 and position.y > 0 and position.y < 1 then
            local pin = self:GetMap():AcquirePin("BtWQuestsGuidePinTemplate", item.itemName);
            pin.waypoints = waypoints
            pin.item = item

            pin:SetPosition(position.x, position.y);
            pin.Focus:SetShown(false);--item == Guide.Focus)
            pin:Show();
        end
    end
end

BtWQuestsGuidePinMixin = CreateFromMixins(MapCanvasPinMixin);
function BtWQuestsGuidePinMixin:OnLoad()
	self:SetScalingLimits(1, 1.0, 1.2);
	self:UseFrameLevelType("PIN_FRAME_LEVEL_STORY_LINE");
end
function BtWQuestsGuidePinMixin:OnAcquired(itemName)
	self.itemName = itemName;
	self.mapID = self:GetMap():GetMapID();
end
function BtWQuestsGuidePinMixin:SetName(value)
    self.name = value
end
function BtWQuestsGuidePinMixin:OnMouseEnter()
    local tooltip = WorldMapTooltip or GameTooltip
	tooltip:SetOwner(self, "ANCHOR_LEFT");
	tooltip:SetText(self.itemName);
	tooltip:Show();
end
function BtWQuestsGuidePinMixin:OnMouseLeave()
    local tooltip = WorldMapTooltip or GameTooltip
	tooltip:Hide();
end
function BtWQuestsGuidePinMixin:OnClick(button)
    if button == "RightButton" or (button == "LeftButton" and IsControlKeyDown()) then
        self.waypoints[self.item] = nil
		self:GetMap():RemovePin(self);
    elseif button == "LeftButton" then
        Guide:SetFocus(self.item)
    end
end

if C_Map and C_Map.SetUserWaypoint then
    hooksecurefunc(C_Map, "SetUserWaypoint", function (waypoint)
        if Guide.UserWaypoint ~= waypoint then
            Guide.UserWaypoint = nil
        end
    end)
    hooksecurefunc(C_Map, "ClearUserWaypoint", function ()
        if Guide.UserWaypoint then
            Guide.UserWaypoint = nil
            Guide.Waypoints[Guide.Focus.mapId][Guide.Focus] = nil
            Guide.DataProvider:RefreshAllData()
        end
    end)
end
